package org.teremail.smtp;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;

import org.apache.mina.common.IoAcceptor;
import org.apache.mina.common.IoFilter;
import org.apache.mina.common.IoHandler;
import org.apache.mina.filter.LoggingFilter;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.nio.SocketAcceptor;
import org.apache.mina.transport.socket.nio.SocketAcceptorConfig;
import org.teremail.common.Log;
import org.teremail.delivery.Exchange;
import org.teremail.service.Serviceable;
import org.teremail.service.ServiceAdapter;
import org.teremail.service.ServiceRegistrar;

import com.google.inject.Inject;

public class SMTPService extends ServiceAdapter implements Serviceable {

    private final static Log log = Log.getLog(SMTPService.class);
    private final IoHandler ioHandler;
    private final SocketAcceptorConfig cfg;
    private final InetSocketAddress addr;
    private IoAcceptor acceptor;
    
    public SMTPService(Exchange exchange, String host, int port) {
        cfg = new SocketAcceptorConfig();
        cfg.getFilterChain().addLast("logger", new LoggingFilter());
        IoFilter textProto = new ProtocolCodecFilter(
                new TextLineCodecFactory(Charset.forName("US-ASCII")));
        cfg.getFilterChain().addLast("codec", new ConditionalFilter(textProto));
        ioHandler = new SMTPIOHandler(new SMTPCommandParser(), 
                new MessageDataConsumerFactory(exchange));
        this.addr = new InetSocketAddress(host, port);
    }
    
    public void bind() throws IOException {
        acceptor = new SocketAcceptor();
        acceptor.bind(addr, ioHandler, cfg);
        log.info("Server bound, listening on port: %d", addr.getPort());
    }
    
    public void unbind() throws IOException {
        acceptor.unbindAll();
        log.info("Server unbound");
    }

    @Inject
    public void registerService(ServiceRegistrar serviceRegistrar) {
        serviceRegistrar.register(this);
    }
}
